package com.computechinc.earthquake.client;

import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.HorizontalSplitPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.XMLParser;

/*
 * 
 * 
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Earthquake implements EntryPoint {
	// Miscellaneous
	private static final String BLANK = "";
	
	// Styles
	//private static final String USER_TABLE_LABEL_STYLE = "userTableLabel";
	//private static final String USER_TABLE_STYLE = "userTable";
	//private static final String NOTES_STYLE = "notes";
	
	// XML Data
	private ArrayList<QuakeData> data = new ArrayList<QuakeData>();
	private final DateTimeFormat dateFmt = 
			DateTimeFormat.getFormat( "hh:mm:ss aa zzz, MM/dd/yyyy" );
	private String basePath = BLANK;
	
	// UI Objects
	private HorizontalSplitPanel horizSplitPanel = null;
	
	/**
	 * This is the entry point method. It has a known SOP issue in IE7/8.
	 * The issue is documented here: 
	 * http://code.google.com/p/google-web-toolkit/issues/detail?id=3795.
	 * 
	 * The SOP issue may be avoided by unchecking "Enable native
	 * XMLHTTP support" from the advanced options in IE7/8.
	 */
	public void onModuleLoad() {
		RequestBuilder reqBuilder = new RequestBuilder( RequestBuilder.GET,
														"../7day-M5.xml" );
		try {
			reqBuilder.sendRequest( null, new RequestCallback() {
				@Override
				public void onError( Request req, Throwable e ) {
					requestFailed( e );
				}
				
				@Override
				public void onResponseReceived( Request req, Response resp ) {
					parseXML( resp.getText() );
					renderXML();
				}
			} );
		} catch ( RequestException e ) {
			requestFailed( e );
		}
	}
	
	/**
	 * Parses the XML into an ArrayList. A good reference on how
	 * to parse XML may be found here:
	 * www.roseindia.net/tutorials/gwt/retrieving-xml-data.shtml
	 * 
	 * @param xmlText the XML text read in from the file.
	 */
	private void parseXML( String xmlText ) {
		DateTimeFormat fmt = 
			DateTimeFormat.getFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'" );
		String id = BLANK, title = BLANK, summary = BLANK,
			point = BLANK, category = BLANK;
		Date updated = null;
		double lat = 0.0, lon = 0.0, elev = 0.0;
		char age = ' ';
		Document dom = XMLParser.parse( xmlText );
		Element doc = dom.getDocumentElement();
		XMLParser.removeWhitespace( doc );
		
		basePath = (( Element )doc.getElementsByTagName( "link" ).item( 1 )).getAttribute( "href" );
		
		data.clear(); // Clear the data
		NodeList elems = doc.getElementsByTagName( "entry" );
		for ( int i = 0; i < elems.getLength(); i++ ) {
			Element elem = (Element)elems.item( i );
			
			// Collect the data from the XML text
			id = getElementTextValue( elem, "id" );
			title = getElementTextValue( elem, "title" );
			try {
				updated = fmt.parse( getElementTextValue( elem, "updated" ) );
			} catch ( IllegalArgumentException e ) {
				System.err.println( "Problem parsing the updated date." );
				updated = new Date( 0 );
			}
			summary = getElementTextValue( elem, "summary" );
			point = getElementTextValue( elem, "point" );
			int pos = point.indexOf( ' ' );
			lat = Double.parseDouble( point.substring( 0, pos ) );
			lon = Double.parseDouble( point.substring( pos + 1 ) );
			elev = Double.parseDouble( getElementTextValue( elem, "elev" ) );
			category = ((Element)elem.getElementsByTagName( "category" ).item( 0 )).getAttribute( "term" );
			pos = category.indexOf( ' ' );
			age = Character.toUpperCase( category.charAt( pos + 1 ) );
			
			// Add a new QuakeData object
			data.add( new QuakeData( id, title, updated, summary, 
									 lat, lon, elev, age ) );
		}
	}
	
	/**
	 * The main method for rendering the RIA.
	 */
	private void renderXML() {
		horizSplitPanel = new HorizontalSplitPanel();
		RootPanel.get( "earthquakes").add( horizSplitPanel );
		horizSplitPanel.setLeftWidget( setupList() );
		horizSplitPanel.setRightWidget( setupDetails() );
	}
	
	/**
	 * Sets up the left-hand side of the split panel for the
	 * listing of information.
	 * 
	 * @param panel
	 */
	private Widget setupList() {
		HorizontalPanel panel = new HorizontalPanel();
		Tree t = new Tree();
		TreeItem ti = null;
		Label l = null;
		
		for ( final QuakeData d : data ) {
			l = new Label( d.getTitle() );
			l.addClickHandler( new ClickHandler() {
				@Override
				public void onClick( ClickEvent event ) {
					changeDetails( d.getSummary() );
				}
			} );
			ti = new TreeItem( l );
			ti.addItem( "<b>ID:</b> " + d.getId() );
			ti.addItem( "<b>Last Updated:</b> " + dateFmt.format( d.getUpdated() ) );
			ti.addItem( "<b>Coordinates:</b> (" + d.getLat() + ", " + d.getLon() + ")" );
			ti.addItem( "<b>Elevation:</b> " + d.getElev() + " m" );
			ti.addItem( "<b>Age:</b> " + QuakeData.ages.get( d.getAge() ) );
			
			t.addItem( ti );
		}
		panel.add( t );
		
		return panel;
	}
	
	private Widget setupDetails() {
		HTMLPanel panel = new HTMLPanel( "" );

		return panel;
	}
	
	private void changeDetails( String html ) {
		horizSplitPanel.setRightWidget( new HTMLPanel( html ) );
	}
	
	// Utility methods
	private void requestFailed( Throwable e ) {
		Window.alert( "Failed to send the message: " + e.getMessage() );
	}
	
	private String getElementTextValue( Element parent, String tag ) {
		return parent.getElementsByTagName( tag ).item( 0 ).getFirstChild().getNodeValue();
	}
}
